using DataService.Helper;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DataService.Service
{
    public class FileCollection<T>
        where T : new()
    {
        LogHelper logHelper = new LogHelper();
        private System.Threading.Timer monitoringFileTimer = null;
        string path = "", filter = "";
        FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
        /// <summary>
        /// 回调函数
        /// </summary>
        public MethodInfo Method { get; set; }
        public T Entity { get; set; }

        public bool Status { get; set; }
        public FileCollection()
        {

        }
        public FileCollection(T entity, MethodInfo method, string path, string filter)
        {
            Entity = entity;
            Method = method;
            this.path = path;
            this.filter = filter;
            Status = StartWatcher(path, filter);
        }

        private void OnMonitoringTimerCallback(object state)
        {
            fileSystemWatcher.Dispose();
            fileSystemWatcher = new FileSystemWatcher();
            InitWatch();
        }
        /// <summary>
        /// 开始监听文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filter"></param>
        public bool StartWatcher(string path, string filter)
        {
            this.path = path;
            this.filter = filter;

            monitoringFileTimer = new System.Threading.Timer((TimerCallback)OnMonitoringTimerCallback, path + "|" + filter,
                            TimeSpan.Zero, TimeSpan.FromSeconds(10));
            InitWatch();
            return true;
        }

        private void InitWatch()
        {
            fileSystemWatcher.Path = path;
            fileSystemWatcher.NotifyFilter = NotifyFilters.LastAccess
                                           | NotifyFilters.LastWrite
                                             | NotifyFilters.FileName
                                             | NotifyFilters.DirectoryName;
            //文件类型，支持通配符，“*.txt”只监视文本文件
            fileSystemWatcher.Filter = filter;    // 监控的文件格式
            fileSystemWatcher.IncludeSubdirectories = true;  // 监控子目录
            fileSystemWatcher.Changed += new FileSystemEventHandler(OnProcess);
            fileSystemWatcher.Created += new FileSystemEventHandler(OnProcess);
            fileSystemWatcher.Renamed += new RenamedEventHandler(OnRenamed);
            fileSystemWatcher.Deleted += new FileSystemEventHandler(OnProcess);
            //表示当前的路径正式开始被监控，一旦监控的路径出现变更，FileSystemWatcher 中的指定事件将会被触发。
            fileSystemWatcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// 开始监听文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="filter"></param>
        public void StopWatcher(string path, string filter)
        {
            fileSystemWatcher.Changed -= new FileSystemEventHandler(OnProcess);
            fileSystemWatcher.Created -= new FileSystemEventHandler(OnProcess);
            fileSystemWatcher.Renamed -= new RenamedEventHandler(OnRenamed);
            fileSystemWatcher.Deleted -= new FileSystemEventHandler(OnProcess);
            if (monitoringFileTimer != null)
            {
                monitoringFileTimer.Dispose();
            }
        }
        /// <summary>
        /// 文件变更
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnProcess(object source, FileSystemEventArgs e)
        {
            if (e.ChangeType == WatcherChangeTypes.Created)
            {
                OnCreated(source, e);
            }
            else if (e.ChangeType == WatcherChangeTypes.Changed)
            {
                OnChanged(source, e);
            }
            else if (e.ChangeType == WatcherChangeTypes.Deleted)
            {
                OnDeleted(source, e);
            }
        }
        /// <summary>
        /// 当创建文件
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnCreated(object source, FileSystemEventArgs e)
        {
            logHelper.Info($"File created: {e.ChangeType} {e.FullPath} {e.Name}");
        }
        /// <summary>
        /// 当文件修改
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            logHelper.Info($"File changed: {e.ChangeType} {e.FullPath} {e.Name}");
            if (!e.Name.Contains("Back_"))
            {
                FileListener(e.FullPath);
            }
        }
        /// <summary>
        /// 文件删除
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnDeleted(object source, FileSystemEventArgs e)
        {
            logHelper.Info($"File deleted: {e.ChangeType} {e.FullPath} {e.Name}");
        }
        /// <summary>
        /// 文件重命名
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnRenamed(object source, FileSystemEventArgs e)
        {
            logHelper.Info($"File renamed: {e.ChangeType} {e.FullPath} {e.Name}");
        }
        /// <summary>
        /// 判断文件是否在用
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private bool IsFileInUse(string fileName)
        {
            try
            {
                FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                fs.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 监听文件变化后，调取回调函数传回数据
        /// </summary>
        /// <param name="fileName"></param>
        private void FileListener(string fileName)
        {
            if (Entity == null || Method == null)
            {
                logHelper.Error("没有配置回调函数！");
                return;
            }
            try
            {
                List<string> contain = GetFileContent(fileName);
                if (contain.Count > 0)
                {
                    Method.Invoke(Entity, new object[] { contain });
                }
            }
            catch (Exception ex)
            {
                logHelper.Error(ex.Message + "\r\n" + ex.StackTrace);
            }
        }

        /// <summary>
        /// 读取文件内容并返回
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public List<string> GetFileContent(string fileName)
        {
            List<string> contain = new List<string>();
            if (fileName.Contains("Back")) return contain;
            try
            {
                FileInfo fileInfo = new FileInfo(fileName);
                while (!IsFileInUse(fileName))
                {
                    Thread.Sleep(1000);
                }
                StreamReader fs = new StreamReader(fileName);
                while (!fs.EndOfStream)
                {
                    string line = fs.ReadLine();
                    contain.Add(line);
                }
                fs.Close();
                if (string.IsNullOrWhiteSpace(path))
                {
                    //取文件的上一级目录
                    DirectoryInfo directoryInfo = new DirectoryInfo(fileName);
                    path = directoryInfo.FullName.Trim().TrimEnd('\\');
                    var arry = path.Split('\\');
                    if (arry.Length > 2)
                    {
                        path = path.Replace(arry.Last(), "");
                    }
                }

                if (!Directory.Exists(path + @"\Back"))
                {
                    Directory.CreateDirectory(path + @"\Back");
                }
                string filePath = $@"{path}\Back\Back_{DateTimeOffset.Now.ToUnixTimeSeconds() + "_" + fileName.Split('\\').Last()}";
                File.Copy(fileName, filePath);
                File.Delete(fileName);
            }
            catch (Exception ex)
            {
                logHelper.Error(ex.Message + "\r\n" + ex.StackTrace);
            }
            return contain;
        }
    }
}
